<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>实现不同效果的轮播</title>

  <style>
    .container {
      max-width: 800px;
      margin: 30px auto;
      border-radius: 4px;
      box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.3);
      padding: 16px;
    }

    .carousel {
      position: relative;
      height: 200px;
      overflow: hidden;
    }

    .carousel .panels > a {
      position: absolute;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      height: 100%;
      text-decoration: none;
      z-index: 1;
    }

    .carousel .panels > a.active {
      z-index: 10;
    }


    .carousel .panels>a:nth-child(even) {
      background-color: lightskyblue;
    }

    .carousel .panels>a:nth-child(odd) {
      background-color: rgb(28, 202, 135);
    }

    .carousel .arrow {
      position: absolute;
      z-index: 100;
      top: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 32px;
      height: 32px;
      border: none;
      border-radius: 50%;
      background-color: rgba(31, 45, 61, .11);
      opacity: 0;
      transition: all .3s;
      cursor: pointer;
      outline: none;
    }

    .carousel .arrow-pre {
      left: 10px;
      transform: translateX(-10px) translateY(-50%);

    }

    .carousel:hover .arrow-pre {
      transform: translateX(0) translateY(-50%);
      opacity: 1;
    }


    .carousel .arrow-next {
      right: 10px;
      transform: translateX(10px) translateY(-50%);
    }

    .carousel:hover .arrow-next {
      transform: translateX(0) translateY(-50%);
      opacity: 1;
    }

    .carousel .arrow::before {
      content: '';
      display: block;
      width: 6px;
      height: 6px;
      border-left: 1px solid #fff;
      border-top: 1px solid #fff;
      transform: rotate(-45deg);
    }

    .carousel .arrow.arrow-next::before {
      transform: rotate(135deg);
    }

    .carousel .indicators {
      position: absolute;
      z-index: 100;
      left: 50%;
      bottom: 10px;
      transform: translateX(-50%);
      list-style: none;
      margin: 0;
      padding: 0;
    }

    .carousel .indicators>li {
      display: inline-block;
      padding: 5px 0;
      cursor: pointer;
    }

    .carousel .indicators>li::before {
      content: '';
      display: block;
      width: 30px;
      height: 2px;

      background-color: #c0c4cc;
      transition: all .3s;
    }

    .carousel .indicators>li.active::before {
      background: #fff;

    }
  </style>
</head>

<body>
  <div class="container">
    <h2>Carousel</h2>
    <div>
      <select id="animation-select">
        <option value="slide">slide</option>
        <option value="fade">fade</option>
        <option value="zoom">zoom</option>
      </select>
    </div>
    <div class="carousel">
      <div class="panels">
        <a class="active" href="#0">0</a>
        <a href="#1">1</a>
        <a href="#2">2</a>
        <a href="#3">3</a>
      </div>
      <div class="arrows">
        <button class="arrow arrow-pre"></button>
        <button class="arrow arrow-next"></button>
      </div>
      <ul class="indicators">
        <li class="active"></li>
        <li></li>
        <li></li>
        <li></li>
      </ul>
    </div>
  </div>

  

  <script>


    const css = ($node, cssobj) => Object.assign($node.style, cssobj)

    const Animation = {
      slide($from, $to, direction) {
        $from.style = ''
        $to.style = ''
        if (direction === 'left') {
          css($from, {
            transform: `translateX(0)`,
            zIndex: 10
          })
          css($to, {
            transform: `translateX(100%)`,
            zIndex: 10
          })
          setTimeout(() => {
            css($from, {
              transform: `translateX(-100%)`,
              transition: `all .3s`
            })
            css($to, {
              transform: `translateX(0)`,
              transition: `all .3s`
            })
          })
        } 
        else if (direction === 'right') {
          css($from, {
            transform: `translateX(0)`
          })
          css($to, {
            transform: `translateX(-100%)`
          })
          setTimeout(() => {
            css($from, {
              transform: `translateX(100%)`,
              transition: `all .3s`
            })
            css($to, {
              transform: `translateX(0)`,
              transition: `all .3s`
            })
          })
        }
      },

      fade($from, $to) {
        $from.style = ''
        $to.style = ''
        css($from, {
          opacity: 1,
          zIndex: 10
        })

        css($to, {
          opacity: 0,
          zIndex: 9
        })

        setTimeout(() => {
          css($from, {
            opacity: 0,
            zIndex: 10,
            transition: `all .3s`
          })

          css($to, {
            opacity: 1,
            zIndex: 9,
            transition: `all .3s`
          })
        })

        setTimeout(() => {
          css($from, {
            zIndex: 9
          })
          css($to, {
            zIndex: 10
          })
        }, 300);
      },

      zoom($from, $to) {
        $from.style = ''
        $to.style = ''
        css($from, {
          transform: `scale(1)`,
          opacity: 1,
          zIndex: 10
        })

        css($to, {
          transform: `scale(10)`,
          opacity: 0,
          zIndex: 9
        })

        setTimeout(() => {
          css($from, {
            transform: `scale(10)`,
            opacity: 0,
            zIndex: 10,
            transition: `all .3s`
          })

          css($to, {
            transform: `scale(1)`,
            opacity: 1,
            zIndex: 9,
            transition: `all .3s`
          })
        })

        setTimeout(() => {
          css($from, {
            zIndex: 9
          })
          css($to, {
            zIndex: 10
          })
        }, 300);
      }
    }




    class Carousel {
      constructor($root, animation) {
        this.$root = $root
        this.$pre = $root.querySelector('.arrow-pre')
        this.$next = $root.querySelector('.arrow-next')
        this.$$indicators = $root.querySelectorAll('.indicators > li')
        this.$$panels = $root.querySelectorAll('.panels >a')
        this.animation = animation

        this.bind()
      }
      bind() {
        //使用箭头函数的写法，箭头函数里面的this还是我们new出来的this
        // this.$pre.onclick = () => {
        //   let index = this.getPreIndex()
        //   this.setPage(index)
        //   this.setIndicator(index)
        // }

        // this.$next.onclick = () => {
        //   let index = this.getNextIndex()
        //   this.setPage(index)
        //   this.setIndicator(index)
        // }

        // this.$$indicators.forEach($indicator => $indicator.onclick = (e) => {
        //   let index = [...this.$$indicators].indexOf(e.target)
        //   this.setPage(index)
        //   this.setIndicator(index)
        // })





        let self = this
        this.$pre.onclick = function () {
          let fromIndex = self.getIndex()
          let toIndex = self.getPreIndex()
          self.setPage(fromIndex, toIndex, 'right')
          self.setIndicator(toIndex)
        }

        this.$next.onclick = function () {
          let fromIndex = self.getIndex()
          let toIndex = self.getNextIndex()
          self.setPage(fromIndex, toIndex, 'left')
          self.setIndicator(toIndex)
        }

        this.$$indicators.forEach($indicator => $indicator.onclick = function (e) {
          let fromIndex = self.getIndex()
          let toIndex = [...self.$$indicators].indexOf(e.target)
          let direction = fromIndex > toIndex ? 'right' : 'left'
          self.setPage(fromIndex, toIndex, direction)
          self.setIndicator(toIndex)
        })

      }

      getIndex() {
        return [...this.$$indicators].indexOf(this.$root.querySelector('.indicators .active'))
      }

      getPreIndex() {
        return (this.getIndex() - 1 + this.$$indicators.length) % this.$$indicators.length
      }

      getNextIndex() {
        return (this.getIndex() + 1) % this.$$indicators.length
      }

      setPage(fromIndex, toIndex, direction) {
        this.animation(this.$$panels[fromIndex], this.$$panels[toIndex], direction)
      }

      setIndicator(index) {
        this.$$indicators.forEach($indicator => $indicator.classList.remove('active'))
        this.$$indicators[index].classList.add('active')
      }

      setAnimation(animation) {
        this.animation = animation
      }
    }
    
    let $carousel = document.querySelector('.carousel')
    

    let carousel = new Carousel($carousel, Animation.slide)

    //new Carousel(document.querySelector('.carousel'), Animation.zoom)

    document.querySelector('#animation-select').onchange = function() {
      carousel.setAnimation(Animation[this.value])
    }

    

    //document.querySelector('.container').forEach($root => new Carousel($root,animation))




  </script>
</body>

</html>